import 'dart:ffi';
import 'dart:io';
import 'package:call/env.dart';
import 'package:call/call.dart';
import 'package:ffi/ffi.dart';
import 'package:path/path.dart';

/*调用过程
	1、可先调用 设置回调函数   OPO_SetModuleCallBack  
	2、调用 打开端口 (回调函数就可以收到称重信息)  OPO_Open 
	3、或可调用 重新获取重量 获取
	4、结束 关闭端口*/

typedef CFNativeVoid = Void Function();
typedef CFDartVoid = void Function();

typedef CFNativeBool = Bool Function();
typedef CFDartBool = bool Function();

typedef CFNativeBoolWithInt = Bool Function(Int8);
typedef CFDartBoolWithInt = bool Function(int);

typedef CFNativeBoolWithStr = Bool Function(Pointer<Utf8>);
typedef CFDartBoolWithStr = bool Function(Pointer<Utf8>);

typedef CFNativeVoidWithStr = Void Function(Pointer<Utf8>);
typedef CFDartVoidWithStr = void Function(Pointer<Utf8>);

typedef CFNativeVoidWithFunc = Void Function(
    Pointer<NativeFunction<CFNativeVoidWithStr>>);
typedef CFDartVoidWithFunc = void Function(
    Pointer<NativeFunction<CFNativeVoidWithStr>>);

typedef CFDartVoidWithModule = void Function(OPOModuleInfo);

void _callBack(Pointer<Utf8> result) {
  String infoString = result.toDartString();
  print(infoString);
}

class ScalessSDK {
  static final ScalessSDK instance = ScalessSDK();

  final String _libPath = 'assets/libscalessdk.so';
  String get _linuxPath {
    String getDebugPath() => join(Directory.current.path,
        'build/linux/x64/debug/bundle', 'data', 'flutter_assets');
    String getReleasePath() =>
        join(Directory.current.path, 'data', 'flutter_assets');
    return isProduct() ? getReleasePath() : getDebugPath();
  }

  static DynamicLibrary? _globalLibray;

  DynamicLibrary get globalLibray {
    if (_globalLibray != null) {
      return _globalLibray!;
    }
    late DynamicLibrary scalessLib;
    if (Platform.isLinux) {
      scalessLib = DynamicLibrary.open(join(_linuxPath, _libPath));
    } else {
      scalessLib = getDyLibModule(_libPath);
    }
    _globalLibray = scalessLib;
    return scalessLib;
  }

  late CFDartVoidWithStr _moduleCallBack;

  //1、打开端口
  // function OPO_Open(sConnect: PAnsiChar): Integer; stdcall;
  // 参数说明
  // 	sConnect：	串口名称 + ":" + 波特率    或 串口名称（默认波特率115200）
  // 返回： 0：失败  1：成功
  // 例： com1:115200   或  com1c
  bool opoOpen() {
    var result = globalLibray
        .lookupFunction<CFNativeBoolWithStr, CFDartBoolWithStr>('OPO_Open');
    String sConnect = "ttyS1";
    return result(sConnect.toNativeUtf8());
  }

  //2、关闭端口
  bool opoClose() {
    var result =
        globalLibray.lookupFunction<CFNativeBool, CFDartBool>('OPO_Close');
    return result();
  }

  //3、获取重量
  //数据格式 ："sMode,sStatus,sZero,sUnit,sNetWeight,sTareWeight,sGrossWeight"
  bool opoGetResult(String sWeight) {
    var result =
        globalLibray.lookupFunction<CFNativeBoolWithStr, CFDartBoolWithStr>(
            'OPO_GetResult');
    return result(sWeight.toNativeUtf8());
  }

  //4、去皮
  bool opoTare() {
    var result =
        globalLibray.lookupFunction<CFNativeBool, CFDartBool>('OPO_Tare');
    return result();
  }

  //5、归零
  bool opoZero() {
    var result =
        globalLibray.lookupFunction<CFNativeBool, CFDartBool>('OPO_Zero');
    return result();
  }

  //6、设置回调函数
  void opoSetModuleCallBack(CFDartVoidWithModule callback) {
    _moduleCallBack = (Pointer<Utf8> result) {
      String infoString = result.toDartString();
      print(infoString);
      callback(OPOModuleInfo());
    };
    var result =
        globalLibray.lookupFunction<CFNativeVoidWithFunc, CFDartVoidWithFunc>(
            'OPO_SetModuleCallBack');
    result(Pointer.fromFunction<CFNativeVoidWithStr>(_callBack));
  }

  //7、主动上传模式
  bool opoSetAutoMode() {
    var result = globalLibray
        .lookupFunction<CFNativeBool, CFDartBool>('OPO_SetAutoMode');
    return result();
  }

  //8、预制去皮命令
  //value：以 g 为单位
  bool opoPretare(int value) {
    var result = globalLibray
        .lookupFunction<CFNativeBoolWithInt, CFDartBoolWithInt>('OPO_PreTare');
    return result(value);
  }
}

enum OPOModeType {
  none, //"净重称量"
  tare, //"去皮称量"
  pretare //"预制去皮称量"
}

extension OPOModeTypeExtension on OPOModeType {
  static OPOModeType init(String sMode) {
    switch (sMode) {
      case "N":
        return OPOModeType.none;
      case "T":
        return OPOModeType.tare;
      case "P":
        return OPOModeType.pretare;
      default:
        return OPOModeType.none;
    }
  }
}

enum OPOStatusType {
  floor, //"重量溢出或没有开机归零"
  stable, //"重量稳定"
  unstable //"重量不稳定"
}

extension OPOStatusTypeExtension on OPOStatusType {
  static OPOStatusType init(String sStatus) {
    switch (sStatus) {
      case "F":
        return OPOStatusType.floor;
      case "S":
        return OPOStatusType.stable;
      case "U":
        return OPOStatusType.unstable;
      default:
        return OPOStatusType.stable;
    }
  }
}

class OPOModuleInfo {
  OPOModeType sMode;
  OPOStatusType sStatus;
  bool sZero;
  int sUnit;
  int sNetWeight;
  int sTareWeight;
  int sGrossWeight;

  OPOModuleInfo({
    this.sMode = OPOModeType.none,
    this.sStatus = OPOStatusType.stable,
    this.sZero = false,
    this.sUnit = 0,
    this.sNetWeight = 0,
    this.sTareWeight = 0,
    this.sGrossWeight = 0,
  });
}
